import java.io.*;
import java.net.*;
import java.util.Random;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args){
        if (args.length != 5) {
            System.err.println("用法: java Client <serverIP> <serverPort> <Lmin> <Lmax> <N>");
            return;
        }
        String serverIP = args[0];
        int serverPort = Integer.parseInt(args[1]);
        int lmin = Integer.parseInt(args[2]);//最小分块长度
        int lmax = Integer.parseInt(args[3]);//最大分块长度
        int n = Integer.parseInt(args[4]);//分块数量

        //读取 input.txt 文件内容
        String fileContent = readFile("input.txt");
        if (fileContent == null || fileContent.isEmpty()) {
            System.err.println("文件内容为空");
            return;
        }
        int totalLength = fileContent.length();

        // 验证文件长度
        if (totalLength < n * lmin) {
            System.err.println("错误：文件长度(" + totalLength + ")小于最小分块要求(" + n * lmin + ")");
            return;
        }

        // 1. 预先计算分块方案
        int[] chunkLengths = new int[n];
        Random random = new Random();
        int remaining = totalLength;

        for (int i = 0; i < n - 1; i++) {
            //计算最大允许长度
            int maxAllowed = Math.min(lmax, remaining - (n - i - 1) * lmin);

            //安全验证
            if (maxAllowed < lmin) {
                System.err.println("错误：无法满足分块要求");
                return;
            }

            //确保随机范围有效
            int range = maxAllowed - lmin;
            if (range <= 0) {
                //若分配最大允许长度小于最小长度，使用最小长度
                chunkLengths[i] = lmin;
            } else {
                chunkLengths[i] = lmin + random.nextInt(range);
            }
            remaining -= chunkLengths[i];
        }
        chunkLengths[n-1] = remaining; // 最后一块

        try (Socket socket = new Socket(serverIP, serverPort);
             DataOutputStream out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
             DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()))) {

            //发送初始化消息
            out.writeShort(1); //Type=1
            out.writeInt(n);   //N
            out.flush();
            System.out.println("已发送初始化消息，N = " + n);

            //接收同意消息
            short type = in.readShort();
            if (type != 2) {
                System.err.println("未收到同意消息");
                return;
            }

            //存储接收到的反转块
            String[] reversedBlocks = new String[n];
            int startIndex = 0;

            for (int i = 0; i < n; i++) {
                int length = chunkLengths[i];
                String data = fileContent.substring(startIndex, startIndex + length);

                //显示发送的原始文本
                System.out.println("发送第 " + (i+1) + " 块: " + data);
                byte[] dataBytes = data.getBytes("UTF-8");

                //发送反转请求
                out.writeShort(3); // Type=3
                out.writeInt(dataBytes.length);
                out.write(dataBytes);
                out.flush();

                //接收反转应答
                type = in.readShort();
                if (type == 4) {
                    int revLength = in.readInt();
                    byte[] revData = new byte[revLength];
                    in.readFully(revData);
                    String reversed = new String(revData, "UTF-8");

                    //存储反转块
                    reversedBlocks[i] = reversed;
                    System.out.println("接收第 " + (i+1) + " 块反转结果: " + reversed);
                }
                startIndex += length;
            }

            //2. 拼接所有反转块（按逆序）
            StringBuilder finalReversed = new StringBuilder();
            for (int i = n - 1; i >= 0; i--) {
                finalReversed.append(reversedBlocks[i]);
            }

            //3. 将最终反转结果写入文件
            writeReversedFile("output.txt", finalReversed.toString());
            System.out.println("整体反转结果已写入 output.txt: " + finalReversed.toString());

        } catch (Exception e) {
            System.err.println("客户端异常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 读取文件
     * @param fileName
     * @return
     */
    private static String readFile(String fileName) {
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line);
                //保留换行符
                if (reader.ready()) content.append("\n");
            }
        } catch (IOException e) {
            System.err.println("读取文件异常: " + e.getMessage());
        }
        return content.toString();
    }

    /**
     * 写入文件
     * @param fileName
     * @param content
     */
    private static void writeReversedFile(String fileName, String content) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
            writer.write(content);
        } catch (IOException e) {
            System.err.println("写入文件异常: " + e.getMessage());
        }
    }
}